%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
#include "yy.h"

#ifdef DEBUG
#define SHOW_TOKEN(i) fprintf(stderr, "lex: Token\t- %s\n", (i))
#define SHOW_IDENTIFIER(i) fprintf(stderr, "lex: Identifier\t- <%s>\n", (i))
#define SHOW_INTEGER(i) fprintf(stderr, "lex: Integer\t- |%d|\n", (i))
#define SHOW_STRING(i) fprintf(stderr, "lex: String\t- \"%s\"\n", (i))
#else
#define SHOW_TOKEN(i)
#define SHOW_IDENTIFIER(i)
#define SHOW_INTEGER(i)
#define SHOW_STRING(i)
#endif
%}

D	[0-9]
L	[a-zA-Z_]

%%

"int"			{ SHOW_TOKEN("INT"); return INT; }
"enum"			{ SHOW_TOKEN("ENUM"); return ENUM; }
"bool"			{ SHOW_TOKEN("BOOL"); return BOOL; }
"event"			{ SHOW_TOKEN("EVENT"); return EVENT; }
"cont"			{ SHOW_TOKEN("CONT"); return CONT; }

"top"			{ SHOW_TOKEN("TOP"); return TOP; }
"bottom"		{ SHOW_TOKEN("BOTTOM"); return BOTTOM; }
"random"		{ SHOW_TOKEN("RANDOM"); return RANDOM; }
"value"			{ SHOW_TOKEN("VALUE"); return VALUE; }
"size"			{ SHOW_TOKEN("SIZE"); return SIZE; }
"fill"			{ SHOW_TOKEN("FILL"); return FILL; }
"shuffle"		{ SHOW_TOKEN("SHUFFLE"); return SHUFFLE; }
"peek"			{ SHOW_TOKEN("PEEK"); return PEEK; }
"remove"		{ SHOW_TOKEN("REMOVE"); return REMOVE; }
"insert"		{ SHOW_TOKEN("INSERT"); return INSERT; }
"extract"		{ SHOW_TOKEN("EXTRACT"); return EXTRACT; }
"combine"		{ SHOW_TOKEN("COMBINE"); return COMBINE; }

"=="			{ SHOW_TOKEN("EQ"); return EQ; }
"!="			{ SHOW_TOKEN("NE"); return NE; }
"<"			{ SHOW_TOKEN("LT"); return LT; }
"<="			{ SHOW_TOKEN("LE"); return LE; }
">"			{ SHOW_TOKEN("GT"); return GT; }
">="			{ SHOW_TOKEN("GE"); return GE; }

"+"			{ SHOW_TOKEN("ADD"); return ADD; }
"-"			{ SHOW_TOKEN("SUB"); return SUB; }
"*"			{ SHOW_TOKEN("MUL"); return MUL; }
"/"			{ SHOW_TOKEN("DIV"); return DIV; }
"%"			{ SHOW_TOKEN("MOD"); return MOD; }
"++"			{ SHOW_TOKEN("INC"); return INC; }
"--"			{ SHOW_TOKEN("DEC"); return DEC; }

"&&"			{ SHOW_TOKEN("AND"); return AND; }
"||"			{ SHOW_TOKEN("OR"); return OR; }
"!"			{ SHOW_TOKEN("NOT"); return NOT; }
"true"			{ SHOW_TOKEN("TRUE"); return TRUE; }
"false"			{ SHOW_TOKEN("FALSE"); return FALSE; }

"if"			{ SHOW_TOKEN("IF"); return IF; }
"else"			{ SHOW_TOKEN("ELSE"); return ELSE; }
"while"			{ SHOW_TOKEN("WHILE"); return WHILE; }
"do"			{ SHOW_TOKEN("DO"); return DO; }
"for"			{ SHOW_TOKEN("FOR"); return FOR; }
"break"			{ SHOW_TOKEN("BREAK"); return BREAK; }
"continue"		{ SHOW_TOKEN("CONTINUE"); return CONTINUE; }
"return"		{ SHOW_TOKEN("RETURN"); return RETURN; }
"call"			{ SHOW_TOKEN("CALL"); return CALL; }
"trans"			{ SHOW_TOKEN("TRANS"); return TRANS; }
"input"			{ SHOW_TOKEN("INPUT"); return INPUT; }
"output"		{ SHOW_TOKEN("OUTPUT"); return OUTPUT; }

"("			{ SHOW_TOKEN("LPAREN"); return LPAREN; }
")"			{ SHOW_TOKEN("RPAREN"); return RPAREN; }
"{"			{ SHOW_TOKEN("LBRACE"); return LBRACE; }
"}"			{ SHOW_TOKEN("RBRACE"); return RBRACE; }
"["			{ SHOW_TOKEN("LBRACKET"); return LBRACKET; }
"]"			{ SHOW_TOKEN("RBRACKET"); return RBRACKET; }

"="			{ SHOW_TOKEN("ASSIGN"); return ASSIGN; }
";"			{ SHOW_TOKEN("SEMICOLON"); return SEMICOLON; }
","			{ SHOW_TOKEN("COMMA"); return COMMA; }
"?"			{ SHOW_TOKEN("QUESTION"); return QUESTION; }
":"			{ SHOW_TOKEN("COLON"); return COLON; }

{D}+			{
	yylval.integer = atoi(yytext);
	SHOW_INTEGER(yylval.integer);
	return INTEGER;
}

\"(\\.|[^\\"])*\"	{
	char *buf;

	buf = malloc(yyleng - 1);
	if (buf == NULL) {
		yyerror("malloc() failure");
		exit(1);
	}

	memcpy(buf, yytext + 1, yyleng - 1);
	buf[yyleng - 2] = '\0';

	yylval.string = buf;
	SHOW_STRING(yylval.string);
	return STRING;
}

{L}({L}|{D})*		{
	char *buf;

	buf = malloc(yyleng + 1);
	if (buf == NULL) {
		yyerror("malloc() failure");
		exit(1);
	}

	memcpy(buf, yytext, yyleng);
	buf[yyleng] = '\0';

	yylval.identifier = buf;
	SHOW_IDENTIFIER(yylval.identifier);
	return IDENTIFIER;
}

[ \t\v\n\f]		{ ; /* Ignored */ }
"//".*\n		{ ; /* Line comment */ }
.			{ ; /* Bad characters ignored */ }

%%

